﻿using ED.Common.BaseModel;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace ED.FreeSql.Core
{
    public interface IRepository
    {
    }

    /// <summary>
    /// 仓储,开放主键类型
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TPrimaryKey"></typeparam>
    public interface IRepository<TEntity, TPrimaryKey> : IRepository where TEntity : BaseEntity<TPrimaryKey>, new() where TPrimaryKey : struct
    {
        #region 删除
        int Delete(TPrimaryKey? id);

        int Delete(IEnumerable<TPrimaryKey> ids);

        int Delete(Expression<Func<TEntity, bool>> predicate);

        Task<int> DeleteAsync(TPrimaryKey? id, CancellationToken cancellationToken = default);

        Task<int> DeleteAsync(IEnumerable<TPrimaryKey> ids, CancellationToken cancellationToken = default);

        Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
        #endregion

        #region 强制使用硬删除
        int HardDelete(TPrimaryKey? id);

        int HardDelete(IEnumerable<TPrimaryKey> ids);

        int HardDelete(Expression<Func<TEntity, bool>> predicate);

        Task<int> HardDeleteAsync(TPrimaryKey? id, CancellationToken cancellationToken = default);

        Task<int> HardDeleteAsync(IEnumerable<TPrimaryKey> ids, CancellationToken cancellationToken = default);

        Task<int> HardDeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
        #endregion

        #region 插入
        TEntity Insert(TEntity entity);
        TEntity Insert(object dto);
        ResponseDto Insert<ResponseDto>(object dto) where ResponseDto : class, new();
        List<TEntity> Insert(IEnumerable<TEntity> entitys);
        List<TEntity> Insert<Dto>(IEnumerable<Dto> dtos) where Dto : class, new();
        List<ResponseDto> Insert<Dto, ResponseDto>(IEnumerable<Dto> dtos) where Dto : class, new() where ResponseDto : class, new();

        Task<TEntity> InsertAsync(TEntity entity, CancellationToken cancellationToken = default);
        Task<TEntity> InsertAsync(object dto, CancellationToken cancellationToken = default);
        Task<ResponseDto> InsertAsync<ResponseDto>(object dto, CancellationToken cancellationToken = default) where ResponseDto : class, new();
        Task<List<TEntity>> InsertAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default);
        Task<List<TEntity>> InsertAsync<Dto>(IEnumerable<Dto> dtos, CancellationToken cancellationToken = default);
        Task<List<ResponseDto>> InsertAsync<Dto, ResponseDto>(IEnumerable<Dto> dtos, CancellationToken cancellationToken = default) where Dto : class, new() where ResponseDto : class, new();
        #endregion

        #region 更新
        TEntity Update(TEntity entity);
        TEntity Update(object dto);
        ResponseDto Update<ResponseDto>(object dto) where ResponseDto : class, new();

        List<TEntity> Update(IEnumerable<TEntity> entitys);

        List<TEntity> Update(Expression<Func<TEntity, bool>> predicate, object dto);
        List<ResponseDto> Update<ResponseDto>(Expression<Func<TEntity, bool>> predicate, object dto) where ResponseDto : class, new();

        //异步

        Task<TEntity> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default);
        Task<TEntity> UpdateAsync(object dto, CancellationToken cancellationToken = default);
        Task<ResponseDto> UpdateAsync<ResponseDto>(object dto, CancellationToken cancellationToken = default) where ResponseDto : class, new();

        Task<List<TEntity>> UpdateAsync(IEnumerable<TEntity> entitys, CancellationToken cancellationToken = default);
        Task<List<TEntity>> UpdateAsync(Expression<Func<TEntity, bool>> predicate, object dto, CancellationToken cancellationToken = default);
        Task<List<ResponseDto>> UpdateAsync<ResponseDto>(Expression<Func<TEntity, bool>> predicate, object dto, CancellationToken cancellationToken = default) where ResponseDto : class, new();

        #endregion

        #region 查询
        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="Get{Dto}(TPrimaryKey?)"/>
        /// </remarks>
        /// <param name="id"></param>
        /// <returns></returns>
        TEntity Get(TPrimaryKey? id);

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="Get{Dto}(Expression{Func{TEntity, bool}})"/>
        /// </remarks>
        /// <param name="predicate"></param>
        /// <returns></returns>
        TEntity Get(Expression<Func<TEntity, bool>> predicate);

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetLazy{Dto}(TPrimaryKey?)"/>
        /// </remarks>
        /// <param name="id"></param>
        /// <returns></returns>
        Dto Get<Dto>(TPrimaryKey? id) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="Get{Dto}(TPrimaryKey?)"/>
        /// </remarks>
        /// <param name="id"></param>
        /// <returns></returns>
        Dto GetLazy<Dto>(TPrimaryKey? id) where Dto : class, new();

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetLazy{Dto}(Expression{Func{TEntity, bool}})"/>
        /// </remarks>
        /// <param name="predicate"></param>
        /// <returns></returns>
        Dto Get<Dto>(Expression<Func<TEntity, bool>> predicate) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="Get{Dto}(Expression{Func{TEntity, bool}})"/>
        /// </remarks>
        /// <param name="predicate"></param>
        /// <returns></returns>
        Dto GetLazy<Dto>(Expression<Func<TEntity, bool>> predicate) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetList{Dto}(IEnumerable{TPrimaryKey})"/>
        /// </remarks>
        /// <param name="ids"></param>
        /// <returns></returns>
        List<TEntity> GetList(IEnumerable<TPrimaryKey> ids);

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetListLazy{Dto}(IEnumerable{TPrimaryKey})"/>
        /// </remarks>
        /// <param name="ids"></param>
        /// <returns></returns>
        List<Dto> GetList<Dto>(IEnumerable<TPrimaryKey> ids) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="GetList{Dto}(IEnumerable{TPrimaryKey})"/>
        /// </remarks>
        /// <param name="ids"></param>
        /// <returns></returns>
        List<Dto> GetListLazy<Dto>(IEnumerable<TPrimaryKey> ids) where Dto : class, new();

        long GetCount(Expression<Func<TEntity, bool>> predicate = null);

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetList{Dto}(Expression{Func{TEntity, bool}})"/>
        /// </remarks>
        /// <param name="predicate"></param>
        /// <returns></returns>
        List<TEntity> GetList(Expression<Func<TEntity, bool>> predicate = null);

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetListLazy{Dto}(Expression{Func{TEntity, bool}})"/>
        /// </remarks>
        /// <param name="predicate"></param>
        /// <returns></returns>
        List<Dto> GetList<Dto>(Expression<Func<TEntity, bool>> predicate = null) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="GetList{Dto}(Expression{Func{TEntity, bool}})"/>
        /// </remarks>
        /// <param name="predicate"></param>
        /// <returns></returns>
        List<Dto> GetListLazy<Dto>(Expression<Func<TEntity, bool>> predicate = null) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetPage{Dto}(int, int, Expression{Func{TEntity, bool}})"/>
        /// </remarks>        
        /// <returns></returns>
        PageOut<TEntity> GetPage(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate = null);

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束
        /// </remarks>
        /// <returns></returns>
        PageOut<Dto> GetPage<Dto>(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate = null) where Dto : class, new();

        //异步

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetAsync(Expression{Func{TEntity, bool}}, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<TEntity> GetAsync(TPrimaryKey? id, CancellationToken cancellationToken = default);

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetAsync{Dto}(Expression{Func{TEntity, bool}}, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetLazyAsync{Dto}(TPrimaryKey?, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<Dto> GetAsync<Dto>(TPrimaryKey? id, CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="GetAsync{Dto}(TPrimaryKey?, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<Dto> GetLazyAsync<Dto>(TPrimaryKey? id, CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetLazyAsync{Dto}(Expression{Func{TEntity, bool}}, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<Dto> GetAsync<Dto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="GetAsync{Dto}(Expression{Func{TEntity, bool}}, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<Dto> GetLazyAsync<Dto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetListAsync{Dto}(IEnumerable{TPrimaryKey},CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<TEntity>> GetListAsync(IEnumerable<TPrimaryKey> ids, CancellationToken cancellationToken = default);

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetListLazyAsync{Dto}(IEnumerable{TPrimaryKey},CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<Dto>> GetListAsync<Dto>(IEnumerable<TPrimaryKey> ids, CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="GetListAsync{Dto}(IEnumerable{TPrimaryKey}, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<Dto>> GetListLazyAsync<Dto>(IEnumerable<TPrimaryKey> ids, CancellationToken cancellationToken = default) where Dto : class, new();

        Task<long> GetCountAsync(CancellationToken cancellationToken = default);
        Task<long> GetCountAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetListAsync{Dto}(CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<TEntity>> GetListAsync(CancellationToken cancellationToken = default);

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可添加泛型约束，参考<seealso cref="GetListAsync{Dto}(Expression{Func{TEntity, bool}}, CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetListLazyAsync{Dto}(CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<Dto>> GetListAsync<Dto>(CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="GetListAsync{Dto}(CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<Dto>> GetListLazyAsync<Dto>(CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 即使开启了懒加载，实体中的导航属性也不会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果想将导航属性序列化到前端，可移除泛型约束或换用<seealso cref="GetListLazyAsync{Dto}(Expression{Func{TEntity, bool}},CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<Dto>> GetListAsync<Dto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        /// <summary>
        /// 如果开启了懒加载，那么实体中的导航属性会被序列化到前端
        /// </summary>
        /// <remarks>
        /// 如果不想将导航属性序列化到前端，可换用<seealso cref="GetListAsync{Dto}(Expression{Func{TEntity, bool}},CancellationToken)"/>
        /// </remarks>
        /// <returns></returns>
        Task<List<Dto>> GetListLazyAsync<Dto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        Task<PageOut<TEntity>> GetPageAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default);
        Task<PageOut<TEntity>> GetPageAsync(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

        Task<PageOut<Dto>> GetPageAsync<Dto>(int pageIndex, int pageSize, CancellationToken cancellationToken = default) where Dto : class, new();
        Task<PageOut<Dto>> GetPageAsync<Dto>(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        #endregion

        #region 强制使用硬查询(不需要此功能)
        //TEntity HardGet(TPrimaryKey? id);
        //TEntity HardGet(Expression<Func<TEntity, bool>> predicate);
        //Dto HardGet<Dto>(TPrimaryKey? id) where Dto : class, new();
        //Dto HardGet<Dto>(Expression<Func<TEntity, bool>> predicate) where Dto : class, new();

        //List<TEntity> HardGetList(IEnumerable<TPrimaryKey> ids);
        //List<Dto> HardGetList<Dto>(IEnumerable<TPrimaryKey> ids) where Dto : class, new();

        //long HardGetCount(Expression<Func<TEntity, bool>> predicate = null);

        //List<TEntity> HardGetList(Expression<Func<TEntity, bool>> predicate = null);
        //List<Dto> HardGetList<Dto>(Expression<Func<TEntity, bool>> predicate = null) where Dto : class, new();

        //PageOut<TEntity> HardGetPage(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate = null);
        //PageOut<Dto> HardGetPage<Dto>(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate = null) where Dto : class, new();

        ////异步

        //Task<TEntity> HardGetAsync(TPrimaryKey? id, CancellationToken cancellationToken = default);
        //Task<TEntity> HardGetAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
        //Task<Dto> HardGetAsync<Dto>(TPrimaryKey? id, CancellationToken cancellationToken = default) where Dto : class, new();
        //Task<Dto> HardGetAsync<Dto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        //Task<List<TEntity>> HardGetListAsync(IEnumerable<TPrimaryKey> ids, CancellationToken cancellationToken = default);

        //Task<List<Dto>> HardGetListAsync<Dto>(IEnumerable<TPrimaryKey> ids, CancellationToken cancellationToken = default) where Dto : class, new();

        //Task<long> HardGetCountAsync(CancellationToken cancellationToken = default);
        //Task<long> HardGetCountAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

        //Task<List<TEntity>> HardGetListAsync(CancellationToken cancellationToken = default);

        //Task<List<TEntity>> HardGetListAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

        //Task<List<Dto>> HardGetListAsync<Dto>(CancellationToken cancellationToken = default) where Dto : class, new();
        //Task<List<Dto>> HardGetListAsync<Dto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        //Task<PageOut<TEntity>> HardGetPageAsync(int pageIndex, int pageSize, CancellationToken cancellationToken = default);
        //Task<PageOut<TEntity>> HardGetPageAsync(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

        //Task<PageOut<Dto>> HardGetPageAsync<Dto>(int pageIndex, int pageSize, CancellationToken cancellationToken = default) where Dto : class, new();
        //Task<PageOut<Dto>> HardGetPageAsync<Dto>(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) where Dto : class, new();

        #endregion

        #region 审计属性判断
        /// <summary>
        /// 是否是更新审计实体
        /// </summary>
        public bool IsAuditUpdate { get; }

        /// <summary>
        /// 是否是删除审计实体
        /// </summary>
        public bool IsAuditDelete { get; }

        /// <summary>
        /// 是否是插入审计实体
        /// </summary>
        public bool IsAuditInsert { get; }
        #endregion
    }

    /// <summary>
    /// 仓储模型,使用int类型作为主键
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public interface IRepository<TEntity> : IRepository<TEntity, int> where TEntity : BaseEntity<int>, new()
    {

    }
}
